package vn.fpt.fsoft.menugame;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ScreenManager extends JFrame {

	// Define constants for the game
	static final int CANVAS_WIDTH = 800; // width and height of the game screen
	static final int CANVAS_HEIGHT = 600; // width and height of the game screen
	static final int UPDATE_RATE = 60; // number of game update per second
	static final long UPDATE_PERIOD = 1000000000L / UPDATE_RATE; // nanoseconds

	// Define instance variables for the game objects here

	// Handle for the custom drawing panel
	private GameCanvas canvas;

	private List<GameScreen> gameScreens = new ArrayList<GameScreen>();

	// using for copy gameScreens
	private List<GameScreen> gameScreenToUpdates = new ArrayList<GameScreen>();

	// public ScreenManagers(boolean isPopup) {
	// }

	// Constructor to initialize the UI components and game objects
	public ScreenManager() {
		// Initialize the game objects
		gameInit();

		// UI components
		canvas = new GameCanvas();
		canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
		setResizable(false);
		this.setContentPane(canvas);

		// Other UI components such as button, score board, if any.

		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.pack();
		this.setTitle("MY GAME");
		this.setVisible(true);

		// Start the game.
		gameStart();
	}

	// All the game related codes here

	// Initialize all the game objects, run only once in the constructor of the
	// main class.
	public void gameInit() {
		for (int i = 0; i < gameScreens.size(); i++) {
			gameScreens.get(i).gameInit();
		}
	}

	// Shutdown the game, clean up code that runs only once.
	public void gameShutdown() {
		for (int i = 0; i < gameScreens.size(); i++) {
			gameScreens.get(i).gameShutdown();
		}
	}

	// To start and re-start the game.
	public void gameStart() {
		// Create a new thread
		Thread gameThread = new Thread() {
			// Override run() to provide the running behavior of this thread.
			@Override
			public void run() {
				gameLoop();
			}
		};
		// Start the thread. start() calls run(), which in turn calls
		// gameLoop().
		gameThread.start();
	}

	// Run the game loop here.
	private void gameLoop() {

		// Game loop
		long beginTime, timeTaken, timeLeft;
		while (true) {
			beginTime = System.nanoTime();
			gameUpdate();
			// Refresh the display
			repaint();
			// Delay timer to provide the necessary delay to meet the target
			// rate
			timeTaken = System.nanoTime() - beginTime;
			timeLeft = (UPDATE_PERIOD - timeTaken) / 1000000; // in milliseconds
			if (timeLeft < 10)
				timeLeft = 10; // set a minimum
			try {
				// Provides the necessary delay and also yields control so that
				// other thread can do work.
				Thread.sleep(timeLeft);
			} catch (InterruptedException ex) {
			}
		}
	}

	// Update the state and position of all the game objects,
	// detect collisions and provide responses.
	public void gameUpdate() {
		// update logic here

		// clear all screen in list screen temp
		gameScreenToUpdates.clear();

		// copy all gameScreens to gameScreenToUpdates
		for (int i = 0; i < gameScreens.size(); i++) {
			gameScreenToUpdates.add(gameScreens.get(i));
		}

		// Loop as long as there are screens waiting to be updated.
		while (gameScreenToUpdates.size() > 0) {
			// pop mosttop screen
			// GameScreens screen =
			// gameScreenToUpdates.get(gameScreenToUpdates.size() - 1);
			GameScreen screen = gameScreenToUpdates.remove(gameScreenToUpdates
					.size() - 1);

			screen.gameUpdate();
		}
	}

	// Refresh the display. Called back via repaint(), which invoke the
	// paintComponent().
	public void gameDraw(Graphics2D g2d) {

		for (int i = 0; i < gameScreens.size(); i++) {
			gameScreens.get(i).gameDraw(g2d);
		}
	}

	// Process a key-pressed event. Update the current state.
	public void gameKeyPressed(int keyCode) {
		// clear all screen in list screen temp
		gameScreenToUpdates.clear();

		// copy all gameScreens to gameScreenToUpdates
		for (int i = 0; i < gameScreens.size(); i++) {
			gameScreenToUpdates.add(gameScreens.get(i));
		}

		// Loop as long as there are screens waiting to be updated.
		while (gameScreenToUpdates.size() > 0) {
			// pop mosttop screen
			// GameScreens screen =
			// gameScreenToUpdates.get(gameScreenToUpdates.size() - 1);
			GameScreen screen = gameScreenToUpdates.remove(gameScreenToUpdates
					.size() - 1);

			screen.gameKeyPressed(keyCode);
		}
//		for (int i = 0; i < gameScreens.size(); i++) {
//			gameScreens.get(i).gameKeyPressed(keyCode);
//		}
		switch (keyCode) {
		case KeyEvent.VK_UP:
			// ......
			break;
		case KeyEvent.VK_DOWN:
			// ......
			break;
		case KeyEvent.VK_LEFT:
			// ......
			break;
		case KeyEvent.VK_RIGHT:
			// ......
			break;
		}
	}

	// Process a key-released event.
	public void gameKeyReleased(int keyCode) {
	}

	// Process a key-typed event.
	public void gameKeyTyped(char keyChar) {
	}

	// Other methods
	public void addScreen(GameScreen screen) {
		screen.setExisting(false);
		screen.gameInit();
		gameScreens.add(screen);
	}

	public void removeScreen(GameScreen screen) {
		screen.gameShutdown();
		gameScreens.remove(screen);
		gameScreenToUpdates.remove(screen);
	}

	// Custom drawing panel, written as an inner class.
	class GameCanvas extends JPanel implements KeyListener, MouseListener {
		// Constructor
		public GameCanvas() {
			setFocusable(true); // so that can receive key-events
			requestFocus();
			addKeyListener(this);
		}

		// Override paintComponent to do custom drawing.
		// Called back by repaint().
		@Override
		public void paintComponent(Graphics g) {
			Graphics2D g2d = (Graphics2D) g;
			super.paintComponent(g2d); // paint background
			// setBackground(Color.BLACK); // may use an image for background

			// Draw the game objects
			gameDraw(g2d);
		}

		// KeyEvent handlers
		@Override
		public void keyPressed(KeyEvent e) {
			gameKeyPressed(e.getKeyCode());
		}

		@Override
		public void keyReleased(KeyEvent e) {
			gameKeyReleased(e.getKeyCode());
		}

		@Override
		public void keyTyped(KeyEvent e) {
			gameKeyTyped(e.getKeyChar());
		}

		@Override
		public void mouseClicked(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mouseExited(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mousePressed(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}
	}

}
